package repository

import (
	"context"
	"django_blog_gin/internal/dto"
	"django_blog_gin/internal/model"
	"django_blog_gin/internal/svc"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"strconv"
	"strings"

	"github.com/elastic/go-elasticsearch/v8/esapi"
)

type EsArticleRepo struct {
	svcCtx *svc.ServiceContext
}

func NewEsArticleRepo(svcCtx *svc.ServiceContext) *EsArticleRepo {
	return &EsArticleRepo{svcCtx: svcCtx}
}

func (r *EsArticleRepo) DeletedIndex() error {
	esArticle := model.ESArticle{}
	indexName := esArticle.IndexName()
	res, err := r.svcCtx.EsClient.Indices.Delete([]string{indexName})
	if err != nil {
		log.Printf("删除旧索引失败: %v", err)
	}
	body, _ := io.ReadAll(res.Body)
	log.Printf("删除旧索引响应: %s", string(body))
	if res.IsError() {
		body, _ := io.ReadAll(res.Body)
		return fmt.Errorf("删除旧索引失败: %s", string(body))
	}
	return nil
}

// 创建文章索引(类似创建表)
func (r *EsArticleRepo) CreateIndex() error {
	esArticle := model.ESArticle{}
	indexName := esArticle.IndexName()
	mapping := esArticle.ESArticleMapping()
	req := esapi.IndicesCreateRequest{
		Index: indexName,
		Body:  strings.NewReader(mapping),
	}

	res, err := req.Do(context.Background(), r.svcCtx.EsClient)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.IsError() {
		body, _ := io.ReadAll(res.Body)
		return fmt.Errorf("failed to create index: %s, response: %s", res.Status(), string(body))
	}
	return nil

}

// 创建文档(类似创建每一行数据)
func (r *EsArticleRepo) CreateDoc(article *model.BlogArticleDetail) error {
	esArticle := model.ESArticle{
		ID:             article.Id,
		Title:          article.Title,
		Body:           article.Body,
		Tags:           strings.Split(article.Tags, ","),
		AuthorUsername: article.AuthorUsername,
		AuthorID:       article.AuthorId,
		CategoryName:   article.CategoryName,
	}
	indexName := esArticle.IndexName()
	jsonData, _ := json.Marshal(esArticle)

	req := esapi.IndexRequest{
		Index:      indexName,
		DocumentID: strconv.FormatInt(int64(article.Id), 10),
		Body:       strings.NewReader(string(jsonData)),
	}

	res, err := req.Do(context.Background(), r.svcCtx.EsClient)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.IsError() {
		panic(res)
	}
	return nil
}

// 同步文章到ES(到时候使用kafka异步做)
func (r *EsArticleRepo) SyncArticleToES(articleID int) error {
	// 获取文章详情
	detailRepo := NewArticle(r.svcCtx)
	articleDetail, err := detailRepo.GetArticleDetail(articleID)
	if err != nil {
		return fmt.Errorf("获取文章详情失败: %v", err)
	}

	// 转换为ESArticle结构体
	esArticle := model.ESArticle{
		ID:             articleDetail.Id,
		Title:          articleDetail.Title,
		Body:           articleDetail.Body,
		Tags:           strings.Split(articleDetail.Tags, ","),
		AuthorUsername: articleDetail.AuthorUsername,
		CategoryName:   articleDetail.CategoryName,
		AuthorID:       articleDetail.AuthorId,
	}

	// 序列化文章数据
	jsonData, err := json.Marshal(esArticle)
	if err != nil {
		return fmt.Errorf("序列化文章数据失败: %v", err)
	}

	// 执行ES索引请求
	indexName := esArticle.IndexName()
	req := esapi.IndexRequest{
		Index:      indexName,
		DocumentID: strconv.Itoa(esArticle.ID),
		Body:       strings.NewReader(string(jsonData)),
	}

	res, err := req.Do(context.Background(), r.svcCtx.EsClient)
	if err != nil {
		return fmt.Errorf("ES请求执行失败: %v", err)
	}
	defer res.Body.Close()

	// 检查ES响应状态
	if res.IsError() {
		body, _ := io.ReadAll(res.Body)
		return fmt.Errorf("ES索引失败 [%s]: %s", res.Status(), string(body))
	}

	return nil
}

func (r *EsArticleRepo) SearchDoc(req dto.EsSearchArticleReq) ([]model.BlogArticleWithTags, error) {
	var query string
	esArticle := model.ESArticle{}
	limit := req.Limit
	offset := req.Offset
	order := req.Order
	orderPrefix := req.OrderPrefix
	authorID := req.UserId

	if authorID > 0 {
		query = fmt.Sprintf(`{
		"query": {
			"bool": {
				"must": [
					{
						"multi_match": {
							"query": "%s",
							"fields": ["title^3", "body", "tags.text", "category_name.text"],
							"type": "cross_fields",
							"operator": "or"
						}
					},
					{
						"term": {
							"author_id": %d
						}
					}
				]
			}
		},
		"size": %d,
		"from": %d,
		"_source": ["id"]
		}`, req.Keyword, authorID, limit, offset)
	} else {
		query = fmt.Sprintf(`{
		"query": {
			"multi_match": {
			"query": "%s",
			"fields": ["title^3", "body", "tags.text", "category_name.text"],
			"type": "cross_fields",
			"operator": "or"
			}
		},
		"size": %d,
		"from": %d,
		"_source": ["id"]
		}`, req.Keyword, limit, offset)
	}
	reqEs := esapi.SearchRequest{
		Index: []string{esArticle.IndexName()},
		Body:  strings.NewReader(query),
	}
	res, err := reqEs.Do(context.Background(), r.svcCtx.EsClient)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.IsError() {
		panic(res)
	}
	// 正确解析Elasticsearch响应结构
	var esResponse struct {
		Hits struct {
			Hits []struct {
				Source model.ESArticle `json:"_source"`
			} `json:"hits"`
		} `json:"hits"`
	}
	if err := json.NewDecoder(res.Body).Decode(&esResponse); err != nil {
		return nil, fmt.Errorf("解析搜索响应失败: %v", err)
	}
	// 提取_source数据
	resp := make([]*model.ESArticle, len(esResponse.Hits.Hits))
	for i, hit := range esResponse.Hits.Hits {
		resp[i] = &hit.Source
	}
	// 只取id然后查询文章详情
	var ids []int
	for _, item := range resp {
		ids = append(ids, item.ID)
	}
	if len(ids) == 0 {
		return nil, nil
	}
	// 查询文章详情
	detailRepo := NewArticle(r.svcCtx)
	articleList, err := detailRepo.GetArticleWithTagsListQueryIds(ids, authorID, limit, offset, order, orderPrefix)
	if err != nil {
		return nil, fmt.Errorf("查询文章详情失败: %v", err)
	}
	return articleList, nil
}
